const { exec, spawn } = require('child_process');
const { promisify } = require('util');
const OSUtils = require('./osUtils');
const logger = require('./logger');

const execAsync = promisify(exec);

/**
 * 命令工具类
 * 提供跨平台的命令执行功能
 */
class CommandUtils {
  /**
   * 执行命令（异步）
   * @param {string} command 要执行的命令
   * @param {object} options 执行选项
   * @returns {Promise<{stdout: string, stderr: string}>}
   */
  static async execute(command, options = {}) {
    const {
      cwd = process.cwd(),
      timeout = 60000,
      env = process.env,
      encoding = 'utf8',
      shell = true
    } = options;

    // 构建执行选项
    const execOptions = {
      cwd,
      timeout,
      env: { ...process.env, ...env },
      encoding,
      shell: OSUtils.isWindows() ? true : shell, // Windows上强制使用shell
      maxBuffer: 1024 * 1024 * 10 // 10MB buffer
    };

    try {
      logger.info('执行命令', { command, cwd, platform: OSUtils.getPlatform() });
      
      const result = await execAsync(command, execOptions);
      
      logger.info('命令执行成功', { 
        command: command.substring(0, 100), 
        stdout: result.stdout ? result.stdout.substring(0, 200) : '',
        stderr: result.stderr ? result.stderr.substring(0, 200) : ''
      });
      
      return result;
    } catch (error) {
      logger.error('命令执行失败', { 
        command, 
        error: error.message,
        code: error.code,
        signal: error.signal
      });
      throw error;
    }
  }

  /**
   * 执行命令并实时获取输出
   * @param {string} command 要执行的命令
   * @param {object} options 执行选项
   * @param {function} onData 数据回调函数
   * @returns {Promise<number>} 退出码
   */
  static async executeWithStream(command, options = {}, onData = null) {
    const {
      cwd = process.cwd(),
      env = process.env,
      shell = true
    } = options;

    return new Promise((resolve, reject) => {
      const execOptions = {
        cwd,
        env: { ...process.env, ...env },
        shell: OSUtils.isWindows() ? true : shell,
        stdio: ['pipe', 'pipe', 'pipe']
      };

      logger.info('执行流式命令', { command, cwd, platform: OSUtils.getPlatform() });

      let childProcess;
      
      if (OSUtils.isWindows()) {
        // Windows上使用cmd执行
        childProcess = spawn('cmd', ['/c', command], execOptions);
      } else {
        // Unix系统上使用sh执行
        childProcess = spawn('sh', ['-c', command], execOptions);
      }

      let stdout = '';
      let stderr = '';

      childProcess.stdout.on('data', (data) => {
        const output = data.toString();
        stdout += output;
        if (onData) {
          onData('stdout', output);
        }
      });

      childProcess.stderr.on('data', (data) => {
        const output = data.toString();
        stderr += output;
        if (onData) {
          onData('stderr', output);
        }
      });

      childProcess.on('close', (code) => {
        logger.info('流式命令执行完成', { 
          command: command.substring(0, 100), 
          code,
          stdout: stdout.substring(0, 200),
          stderr: stderr.substring(0, 200)
        });
        resolve(code);
      });

      childProcess.on('error', (error) => {
        logger.error('流式命令执行失败', { command, error: error.message });
        reject(error);
      });
    });
  }

  /**
   * 构建跨平台命令
   * @param {string} baseCommand 基础命令
   * @param {string[]} args 参数数组
   * @returns {string} 跨平台命令
   */
  static buildCommand(baseCommand, args = []) {
    return OSUtils.buildCommand(baseCommand, args);
  }

  /**
   * 检查命令是否存在
   * @param {string} command 命令名
   * @returns {Promise<boolean>} 命令是否存在
   */
  static async commandExists(command) {
    try {
      const checkCommand = OSUtils.isWindows() 
        ? `where ${command}` 
        : `which ${command}`;
      
      await this.execute(checkCommand, { timeout: 5000 });
      return true;
    } catch (error) {
      return false;
    }
  }

  /**
   * 获取环境变量
   * @param {string} name 环境变量名
   * @param {string} defaultValue 默认值
   * @returns {string} 环境变量值
   */
  static getEnvVar(name, defaultValue = '') {
    return process.env[name] || defaultValue;
  }

  /**
   * 设置环境变量（仅对当前进程有效）
   * @param {string} name 环境变量名
   * @param {string} value 环境变量值
   */
  static setEnvVar(name, value) {
    process.env[name] = value;
  }

  /**
   * 构建npm/yarn命令
   * @param {string} packageManager 包管理器 (npm, yarn, pnpm)
   * @param {string} command 命令 (install, build, start等)
   * @param {string[]} args 额外参数
   * @returns {string} 完整命令
   */
  static buildPackageManagerCommand(packageManager, command, args = []) {
    const executable = packageManager + (OSUtils.isWindows() ? '.cmd' : '');
    return `${executable} ${command} ${args.join(' ')}`.trim();
  }

  /**
   * 构建Git命令
   * @param {string} gitCommand Git子命令
   * @param {string[]} args 参数
   * @returns {string} Git命令
   */
  static buildGitCommand(gitCommand, args = []) {
    const executable = 'git' + (OSUtils.isWindows() ? '.exe' : '');
    return `${executable} ${gitCommand} ${args.join(' ')}`.trim();
  }

  /**
   * 杀死进程
   * @param {number} pid 进程ID
   * @returns {Promise<void>}
   */
  static async killProcess(pid) {
    try {
      const killCommand = OSUtils.isWindows() 
        ? `taskkill /F /PID ${pid}` 
        : `kill -9 ${pid}`;
      
      await this.execute(killCommand, { timeout: 10000 });
      logger.info('进程已终止', { pid });
    } catch (error) {
      logger.warn('终止进程失败', { pid, error: error.message });
      throw error;
    }
  }

  /**
   * 查找占用端口的进程
   * @param {number} port 端口号
   * @returns {Promise<number|null>} 进程ID或null
   */
  static async findProcessByPort(port) {
    try {
      const command = OSUtils.isWindows()
        ? `netstat -ano | findstr :${port}`
        : `lsof -ti:${port}`;
      
      const result = await this.execute(command, { timeout: 10000 });
      
      if (OSUtils.isWindows()) {
        // 解析Windows netstat输出
        const lines = result.stdout.split('\n');
        for (const line of lines) {
          if (line.includes('LISTENING')) {
            const parts = line.trim().split(/\s+/);
            const pid = parseInt(parts[parts.length - 1]);
            if (!isNaN(pid)) {
              return pid;
            }
          }
        }
      } else {
        // Unix系统直接返回PID
        const pid = parseInt(result.stdout.trim());
        if (!isNaN(pid)) {
          return pid;
        }
      }
      
      return null;
    } catch (error) {
      logger.warn('查找端口进程失败', { port, error: error.message });
      return null;
    }
  }

  /**
   * 获取环境变量
   * @returns {object} 环境变量对象
   */
  static getEnvironmentVariables() {
    return { ...process.env };
  }

  /**
   * 设置环境变量
   * @param {object} env 现有环境变量
   * @param {string} key 变量名
   * @param {string} value 变量值
   * @returns {object} 更新后的环境变量
   */
  static setEnvironmentVariable(env, key, value) {
    return { ...env, [key]: value };
  }

  /**
   * 等待端口可用
   * @param {number} port 端口号
   * @param {number} timeout 超时时间（毫秒）
   * @returns {Promise<boolean>} 是否可用
   */
  static async waitForPort(port, timeout = 30000) {
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
      try {
        const processes = await this.findProcessByPort(port);
        if (processes.length === 0) {
          return true;
        }
        await new Promise(resolve => setTimeout(resolve, 1000));
      } catch (error) {
        // 端口检查失败，可能端口已可用
        return true;
      }
    }
    
    return false;
  }
}

module.exports = CommandUtils;